package algorithm;

import data.Data;
import data.Option;

public abstract class AbstractSketch {
	
	private String name;
	
	protected AbstractSketch(String name){
		this.name = name;
	}
	
	public void run(double eps, double confidence, Data data){
		
		System.out.println(name + " algo");
		int[] stream = data.getItems();
		
		int[] actualFreq = new int[data.getMaxScale()];
        for (Integer x : stream)
        {
            actualFreq[x]++;
//          System.out.println("item : " + x);
//          System.out.println("Actual Frequency of [" + x + "]: " + actualFreq[x]);
        }
        Runtime runtime = Runtime.getRuntime();
        runtime.gc();
        long totalMemory = runtime.totalMemory();
		long start = System.currentTimeMillis();
		runtime.gc();
		compute(eps, confidence, stream);
		long end = System.currentTimeMillis();
		System.out.println("\tExecution time: \t" + (end - start) + "ms ~ " + (end - start) / 100 + "s");
		runtime.gc();
		long memory = totalMemory - runtime.freeMemory();
		System.out.println("\tUsed memory: \t\t" + memory + " bytes ~ " + Option.bytesToMegabytes(memory) + " megabytes");
		int nbErrors = 0;
		
        for (int i = 0; i < actualFreq.length; ++i)
        {
//        	System.out.println("Actual Frequency of [" + i + "]: " + actualFreq[i]);
            double ratio = 1.0 * (estimateCount(i) - actualFreq[i]) / data.getTotalItems();
            if (ratio > 1.0001)
            {
                nbErrors++;
            }
        }
        
//        System.out.println("Nb of Errors " + nbErrors);
        double pCorrect = 1 - 1.0 * nbErrors / actualFreq.length;
        if (pCorrect > confidence)
        	System.out.println("Confidence reached: \n\tRequired " + confidence + 
        		"\tReached " + pCorrect);
        else 
        	System.out.println("Confidence NOT reached: \n\tRequired " + confidence + 
            		"\tReached " + pCorrect);
        System.out.println("--------------------------------------------------");
	}
	
	public abstract void compute(double eps, double confidence, int[] stream);
	
	public abstract double estimateCount(int item);
}
